﻿using Flattiverse;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace FlattiverseGame
{
    public class BaseShip : IDrawable
    {
        private string shipName;
        private Ship ship;
        private UniverseGroup uni;

        private Thread shipThread;

        private List<Unit> lastSeenUnits;

        private object sync = new object();

        private volatile float scanDirection = 45f;

        private Vector movement = new Vector();
        private Vector shipPos;
        private Vector nextMove = new Vector();

        private List<Vector> shotList = new List<Vector>();

        private volatile bool isRunning = true;
        private volatile bool holding = false;

        private volatile bool loadShield = false;
        private volatile bool repairSelf = false;

        public bool RepairSelf
        {
            get { return repairSelf; }
            set { repairSelf = value; }
        }

        #region Fields

        public bool LoadShield
        {
            get { return loadShield; }
            set { loadShield = value; }
        }

        public UniverseGroup Universe
        {
            get { return uni; }
        }

        public Ship Ship
        {
            get { return ship; }
        }

        public List<Unit> ScannedUnits
        {
            get
            {
                if (lastSeenUnits == null)
                    return null;

                return lastSeenUnits;
            }
        }

        public bool IsActive
        {
            get
            {
                if (ship == null)
                    return false;

                return ship.IsActive;
            }
        }

        public bool IsAlive
        {
            get 
            {
                if (ship == null)
                    return false;

                return ship.IsAlive;
            }
        }
        #endregion

        public BaseShip(UniverseGroup uni, string shipName)
        {
            this.uni = uni;
            this.shipName = shipName;

            shipThread = new Thread(ShipWorker);
        }

        public void CreateShip(string @class)
        {
            ship = uni.RegisterShip(@class, shipName);

            shipThread.Start();
        }

        private void Scan()
        {
            try
            {
                List<Unit> currentList;
                if (lastSeenUnits != null && lastSeenUnits.Count > 0)
                    currentList = new List<Unit>(lastSeenUnits);
                else
                    currentList = new List<Unit>();

                for (int i = 0; i < ship.ScannerCount; i++)
                {
                    List<Unit> tempList = ship.Scan(scanDirection, ship.ScannerArea.ExtendedLimit);
                    scanDirection += ship.ScannerDegreePerScan;

                    if (currentList.Count == 0)
                        currentList.AddRange(tempList);
                    else
                        foreach (Unit u in tempList)
                        {
                            foreach (Unit unit in currentList)
                                if (unit.Name == u.Name)
                                {
                                    currentList.Remove(unit);
                                    break;
                                }

                            u.Tag = (int)0;
                            currentList.Add(u);
                        }
                }

                for (int i = 0; i < currentList.Count; i++)
                {
                    Unit u = currentList[i];

                    if (u.Tag == null)
                        u.Tag = (int)0;

                    u.Tag = (int)(u.Tag) + 1;

                    if ((int)(u.Tag) > 4)
                    {
                        currentList.Remove(u);
                        i--;
                    }
                }

                lastSeenUnits = currentList;


            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

        private void ShipWorker()
        {
            while (isRunning)
            {
                if (ship != null && ship.IsAlive)
                {
                    Scan();

                    Move();

                    LoadShields();

                    Repair();

                    uni.Wait();
                }
                Thread.Sleep(1);
            }
        }

        private void Repair()
        {
            try
            {
                if (repairSelf)
                {
                    if (ship.Energy / ship.EnergyMax > 0.8f && ship.Hull / ship.HullMax < 0.5f)
                        ship.RepairHull(ship.HullRepair.ExtendedLimit);
                }
            }
            catch { }
        }

        private void LoadShields()
        {
            try
            {
                if (loadShield)
                {
                    if (ship.Energy / ship.EnergyMax > 0.8f && ship.Shield / ship.ShieldMax < 0.5f)
                        ship.LoadShields(ship.ShieldLoad.Limit);
                }
            }
            catch { }
        }

        private void Move()
        {

            if (holding)
                HoldPosition();
            else
            {
                movement = Vector.FromNull();
                float grav = 0f;
                foreach (Unit u in lastSeenUnits)
                    if (u.Mobility == Mobility.Still && u.Gravity > grav)
                        movement = u.Movement;

                movement.Length /= -1f;

                try
                {
                    ship.Move(nextMove);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }



        public void HoldPosition()
        {
            movement = Vector.FromNull();

            foreach (Unit u in lastSeenUnits)
                if (u.Mobility == Mobility.Still && u.Movement > movement)
                    movement = u.Movement;

            if (movement > ship.EngineAcceleration.Limit)
                movement.Length = ship.EngineAcceleration.Limit;

            try
            {
                ship.Move(movement);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

        public void Continue()
        {
            if (ship != null && !ship.IsAlive)
                ship.Continue();
        }

        public void RemoveShip()
        {
            if (ship != null)
            {
                isRunning = false;

                while (shipThread.IsAlive)
                    Thread.Sleep(1);

                ship.Close();
            }
        }

        public void MoveShip(Vector move, float scale)
        {
            move.Length *= 0.02f;

            if (move > ship.EngineAcceleration.Limit)
                move.Length = ship.EngineAcceleration.Limit;

            if (move.Length > 0.6)
                holding = false;
            else
                holding = true;

            nextMove = move;

            scanDirection = move.Angle;
        }

        public void HoldShip()
        {
            holding = true;
        }

        public void Shoot(Vector direction, float scale)
        {
            float originalLength = direction.Length;

            if (direction > ship.WeaponShot.Speed.ExtendedLimit)
                direction.Length = ship.WeaponShot.Speed.ExtendedLimit;

            float time = (originalLength / direction.Length) * scale;

            if (time > ship.WeaponShot.Time.ExtendedLimit)
                time = ship.WeaponShot.Time.ExtendedLimit;

            if (ship != null && ship.WeaponProductionStatus >= 1f && ship.Energy * 4.0f > ship.WeaponShot.ExtendedLimit)
            {
                try
                {
                    //ship.Shoot(direction, (int)time);
                    direction.Angle -= 20f;

                    for (int i = 0; i < 5; i++)
                    {
                        if (direction > ship.WeaponShot.Speed.ExtendedLimit)
                            direction.Length = ship.WeaponShot.Speed.ExtendedLimit;

                        ship.Shoot(direction, direction.Angle, (int)time,
                               ship.WeaponShot.Load.Limit, ship.WeaponShot.DamageHull.Limit,
                               ship.WeaponShot.DamageShield.Limit, ship.WeaponShot.DamageEnergy.Limit, null);

                        direction.Angle += 10f;
                    }

                    //ship.Shoot(direction, direction.Angle, (int)time,
                    //           ship.WeaponShot.Load.Limit, ship.WeaponShot.DamageHull.Limit,
                    //           ship.WeaponShot.DamageShield.Limit, ship.WeaponShot.DamageEnergy.Limit, null);


                    //ship.Shoot(direction, direction.Angle + 20f, (int)time,
                    //           ship.WeaponShot.Load.Limit, ship.WeaponShot.DamageHull.Limit,
                    //           ship.WeaponShot.DamageShield.Limit, ship.WeaponShot.DamageEnergy.Limit, null);

                    //ship.Shoot(direction, direction.Angle + 40f, (int)time,
                    //           ship.WeaponShot.Load.Limit, ship.WeaponShot.DamageHull.Limit,
                    //           ship.WeaponShot.DamageShield.Limit, ship.WeaponShot.DamageEnergy.Limit, null);

                    //ship.Shoot(direction, direction.Angle, (int)time,
                    //           ship.WeaponShot.Load.Limit, ship.WeaponShot.DamageHull.Limit,
                    //           ship.WeaponShot.DamageShield.Limit, ship.WeaponShot.DamageEnergy.Limit, null);

                    //ship.Shoot(direction, direction.Angle - 20f, (int)time,
                    //           ship.WeaponShot.Load.Limit, ship.WeaponShot.DamageHull.Limit,
                    //           ship.WeaponShot.DamageShield.Limit, ship.WeaponShot.DamageEnergy.Limit, null);

                    //ship.Shoot(direction, direction.Angle - 40f, (int)time,
                    //           ship.WeaponShot.Load.Limit, ship.WeaponShot.DamageHull.Limit,
                    //           ship.WeaponShot.DamageShield.Limit, ship.WeaponShot.DamageEnergy.Limit, null);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }
        

        #region Base Draw
        public void Draw(System.Drawing.Graphics graphics, int x, int y, float scale)
        {
            if (ship != null && ship.IsAlive)
            {
                shipPos = new Vector(x, y);



                // Draw Ship
                graphics.FillEllipse(Brushes.RoyalBlue, x - (ship.Radius / scale),
                                                    y - (ship.Radius / scale),
                                                    (ship.Radius * 2) / scale,
                                                    (ship.Radius * 2) / scale);


                // Draw Health
                float healthPercentage = ship.Hull / ship.HullMax;

                graphics.FillRectangle(Brushes.OrangeRed, x - (ship.Radius * 3f) / scale,
                                                          y - (ship.Radius * 2f + GameField.BarHeight * 2f) / scale,
                                                          (ship.Radius * 6f * healthPercentage) / scale,
                                                          GameField.BarHeight / scale);

                // Draw Energy
                float energyPercentage = ship.Energy / ship.EnergyMax;

                graphics.FillRectangle(Brushes.LightBlue, x - (ship.Radius * 3f) / scale,
                                                          y - (ship.Radius * 2f + GameField.BarHeight) / scale,
                                                          (ship.Radius * 6f * energyPercentage) / scale,
                                                          GameField.BarHeight / scale);

                // Draw Shield
                float shieldPercentage = ship.Shield / ship.ShieldMax;

                graphics.FillRectangle(Brushes.CadetBlue, x - (ship.Radius * 3f) / scale,
                                                          y - (ship.Radius * 2f) / scale,
                                                          (ship.Radius * 6f * shieldPercentage) / scale,
                                                          GameField.BarHeight / scale);

                // Draw Move Vector
                //Vector mov = new Vector(nextMove);
                Vector mov = new Vector(nextMove);

                graphics.DrawLine(Pens.White, x, y, x + (mov.X * scale * 4f), y + (mov.Y * scale * 4f));

                mov += Vector.FromXY(movement.X, movement.Y);

                graphics.DrawLine(Pens.LightBlue, x, y, x + (mov.X * scale * 4f), y + (mov.Y * scale * 4f));
            }
        }
        #endregion
    }
}
